document.addEventListener('DOMContentLoaded', function() {
    loadDirectoryContents('/');
    //点击上传按钮
    document.getElementById('upload').addEventListener('click', () => document.getElementById('file-upload').click());
    //监听文件选择=>上传文件
    document.getElementById('file-upload').addEventListener('change', e=>{
        let files = event.target.files;
        let fileArray = [];
        for (let i = 0; i < files.length; i++) {
            fileArray.push(files[i]);
        }
        if (fileArray.length > 0) {
            processFilesAndDirs(fileArray, currentPath);
        }
    });
    //下载选中文件
    document.getElementById('download').addEventListener('click', ()=>{
        let files = [];
        getSelectedFiles().forEach(file => {
            files.push(`/download?path=${file}`)
        });
        downloadAll(files)
        document.querySelectorAll('[name=chkFile]:checked').forEach(x => x.checked=false);
    });
    //移动选中文件/文件夹到指定路径
    document.getElementById('move-to').addEventListener('click', ()=>{
        const destination = prompt('Enter destination path:\n\nExamples:\nPath from root: \u00A0\u00A0\u00A0\u00A0 /Folder\nRelative path: \u00A0\u00A0\u00A0\u00A0 folder1/folder2');
        if (destination) {
            showLoading("  Moving files...  ");
            fetch(`/move?data=${JSON.stringify({ src: getSelectedFiles(), dest: destination })}`, {
                method: 'POST'
            })
                .then(function(response) {
                    if(response.ok) {
                        showNotification("Files moved successfully!");
                        return response.text();
                    }
                    throw new Error('Something went wrong.');
                })  
                .then(function(text) {
                    loadDirectoryContents(currentPath);
                    showNotification("Files moved successfully!");
                })  
                .catch(function(error) {
                    showError('Server error: ' + error);
                });
        }
    });
    //复制选中文件/文件夹到指定路径
    document.getElementById('copy-to').addEventListener('click', ()=>{            
        const destination = prompt('Enter destination path:\n\nExamples:\nPath from root: \u00A0\u00A0\u00A0\u00A0 /Folder\nRelative path: \u00A0\u00A0\u00A0\u00A0 folder1/folder2');
        if (destination) {
            showLoading("  Copying files...  ");
            fetch(`/copy?data=${JSON.stringify({ src: getSelectedFiles(), dest: destination })}`, {
                method: 'POST'
            })
                .then(function(response) {
                    if(response.ok) {
                        showNotification("Files copied successfully!");
                        return response.text();
                    }
                    throw new Error('Something went wrong.');
                })  
                .then(function(text) {
                    loadDirectoryContents(currentPath);
                    showNotification("Files copied successfully!");
                })  
                .catch(function(error) {
                    showError('Server error: ' + error);
                });
        }
    });
    //选中的文件/文件夹重命名
    document.getElementById('rename').addEventListener('click', ()=>{
        const selectedFiles = getSelectedFiles();
        if (selectedFiles.length !== 1) {
            alert('Please select exactly one file to rename.');
            return;
        }
        const newName = prompt('Enter new name:', selectedFiles[0].split('/').pop());

        let new_path = currentPath + '/' + newName;
        new_path = new_path.replace(/\/\//g, '/');

        if (newName) {
            showLoading("  Renaming files...  ");
            fetch(`/rename?data=${JSON.stringify({ old_name: selectedFiles[0], new_name: new_path })}`, {
                method: 'POST'
            })
                .then(function(response) {
                    if(response.ok) {
                        return response.text();
                    }
                    throw new Error('Something went wrong.');
                })  
                .then(function(text) {
                    loadDirectoryContents(currentPath);
                    showPopup('File renamed successfully!');
                })  
                .catch(function(error) {
                    showError('Server error: ' + error);
                });
        }
    });
    //新建文件夹
    document.getElementById('new-folder').addEventListener('click', ()=>{        
        const folder_name = prompt('Enter new folder name:');
        let new_path = currentPath + '/' + folder_name;
        new_path = new_path.replace(/\/\//g, '/');

        if (folder_name) {
            fetch(`/newfolder?data=${JSON.stringify({ foldername: new_path})}`, {
                method: 'POST'
            })
                .then(function(response) {
                    if(response.ok) {
                        return response.text();
                    }
                    throw new Error('Something went wrong.');
                })  
                .then(function(text) {
                    loadDirectoryContents(currentPath);
                    showPopup('Directory created successfully!');
                })  
                .catch(function(error) {
                    showError('Server error: ' + error);
                });
        }
    });
    //删除选中的文件/文件夹
    document.getElementById('delete').addEventListener('click', ()=>{        
        const selectedFiles = getSelectedFiles();
        // if (selectedFiles.length !== 1) {
        //     alert('Please select exactly one file to delete.');
        //     return;
        // }
        showLoading("  Deleting files...  ");
        fetch(`/delete?files=${JSON.stringify(selectedFiles)}`, {
            method: 'DELETE'
        })
            .then(function(response) {
                if(response.ok) {
                    return response.text();
                }
                throw new Error('Something went wrong.');
            })  
            .then(function(text) {
                loadDirectoryContents(currentPath);
                showPopup('Files deleted successfully!');
            })  
            .catch(function(error) {
                showError('Server error: ' + error);
            });
    });
    document.getElementById('popup-close').addEventListener('click', closePopup);
    //保存文件到esp
    document.getElementById("btnSaveFile").addEventListener('click', ()=>{        
        const content=window.fileEditor?window.fileEditor.getValue():txtFileContent.value
        const file=dialogFile.filepath
        if(!content){
            alert("文件内容不能为空！")
            return
        }
        showLoading("  Save files...  ");
        fetch(`/writefile?file=${file}`, {
            method: 'POST',
            body: content
        })
        .then(function(response) {
            if(response.ok) {
                return response.text();
            }
            throw new Error('Something went wrong.');
        })  
        .then(function(text) {
            dialogFile.close()
            loadDirectoryContents(currentPath);
            showPopup('writefile successfully!');
        })  
        .catch(function(error) {
            alert('writefile: ' + error);
        });
    });
    const txtNewFileName=document.getElementById('txtNewFileName')
    //打开新建文件弹窗
    document.getElementById('btnNewFile').addEventListener('click', ()=>{txtNewFileName.value='';document.getElementById("dialogCreateFile").showModal()});
    //关闭弹窗
    document.getElementsByName('btnCloseDialog').forEach(x=>x.addEventListener('click', e=>e.target.offsetParent.close()))
    //确定弹出文件编辑弹窗录入新文件内容
    document.getElementById('btnCreateFile').addEventListener('click', e=>{
        if(!txtNewFileName.value){
            alert('Please enter a file name.');
            txtNewFileName.focus()
            return;
        }
        const path=document.getElementById('breadcrumb').innerText?.replace(/(^\s+|\s+$)/g,'')
        const file=txtNewFileName.value
        e.target.offsetParent.close()
        showEditer(path+file)
    });
    //全选
    document.getElementById('chkAll').addEventListener('click', e=>{
        const checked=e.target.checked;
        document.getElementsByName('chkFile').forEach(el=>{
            el.checked=checked;
        })
    });
    //重启
    document.getElementById('benRestart').addEventListener('click', ()=>{
        fetch(`/restart`)
        .then(res=>{
            if(!res.ok){
                throw new Error('Server error: ' + res.statusText);
            }else{
                showNotification('Restarting...')
                setTimeout(()=>{location.reload()}, 3000)
            }
        }).catch(error => {
            showError(error.message);
        });
    });
    
    updateStatus();
    setInterval(updateStatus, 5000);  // Update every 5 seconds

    
});

let currentPath = '/';
let popup_modal = false;
let popupTimer;




function getSelectedFiles() {
    const result=[]
    document.querySelectorAll('[name=chkFile]:checked').forEach(x => {
        result.push(x.value) 
    });
    return result;
}

function updateStatus() {
    fetch('/status')
        .then(response => response.json())
        .then(data => {
            updateProgressBar(data.progress);
            updateMemoryStatus(data.memoryFree, data.memoryTotal);
        })
        .catch(error => {
            console.error('Error fetching status:', error);
        });
}

function updateProgressBar(progress) {
    const progressBar = document.getElementById('progressbar');
    progressBar.style.width = progress + '%';
    progressBar.style.backgroundColor = `hsl(${(120 * progress) / 100}, 75%, 62%)`;  // Color gradient from red to green
}

function updateMemoryStatus(free, total) {
    const memoryStatus = document.getElementById('memory-status');
    memoryStatus.textContent = `${free}MB / ${total}MB Free`;
}





function allowDrop(event) {
    event.preventDefault();
}

function handleDrop(event) {
    event.preventDefault();
    let items = event.dataTransfer.items;
    if (items.length > 0) {
        handleItems(items);
    }
}


function handleItems(items) {
    let entryPromises = [];
    for (let i = 0; i < items.length; i++) {
        let item = items[i].webkitGetAsEntry();
        if (item) {
            entryPromises.push(processEntry(item, currentPath));
        }
    }

    Promise.all(entryPromises).then(() => {
        loadDirectoryContents(currentPath);
        showNotification("Upload completed successfully!");
    }).catch((error) => {
        showError("Upload failed: " + error.message);
    });
}

function processFilesAndDirs(files, path) {
    let directoryStructure = {};

    for (let file of files) {
        let relativePath = file.webkitRelativePath || file.name;
        let pathParts = relativePath.split('/');
        let currentLevel = directoryStructure;

        for (let i = 0; i < pathParts.length; i++) {
            if (i === pathParts.length - 1) {
                if (!currentLevel._files) {
                    currentLevel._files = [];
                }
                currentLevel._files.push(file);
            } else {
                if (!currentLevel[pathParts[i]]) {
                    currentLevel[pathParts[i]] = {};
                }
                currentLevel = currentLevel[pathParts[i]];
            }
        }
    }

    processDirectoryStructure(directoryStructure, path).then(() => {
        loadDirectoryContents(currentPath);
        showNotification("Upload completed successfully!");
    }).catch((error) => {
        showError("Upload failed: " + error.message);
    });
}

function processDirectoryStructure(structure, path) {
    let promises = [];

    for (let key in structure) {
        if (key === '_files') {
            for (let file of structure._files) {
                promises.push(uploadFileToServer(file, path + '/' + file.name));
            }
        } else {
            let newPath = path + '/' + key;
            promises.push(createDirectory(newPath).then(() => {
                return processDirectoryStructure(structure[key], newPath);
            }));
        }
    }

    return Promise.all(promises);
}

function processEntry(entry, path) {
    return new Promise((resolve, reject) => {
        if (entry.isFile) {
            entry.file(file => {
                uploadFileToServer(file, path + '/' + file.name)
                    .then(resolve)
                    .catch(reject);
            });
        } else if (entry.isDirectory) {
            let newPath = path + '/' + entry.name;
            createDirectory(newPath).then(() => {
                let dirReader = entry.createReader();
                readAllDirectoryEntries(dirReader).then(entries => {
                    let subEntryPromises = entries.map(subEntry => processEntry(subEntry, newPath));
                    Promise.all(subEntryPromises).then(resolve).catch(reject);
                });
            }).catch(reject);
        }
    });
}

function readAllDirectoryEntries(dirReader) {
    let entries = [];
    return new Promise((resolve, reject) => {
        function readEntries() {
            dirReader.readEntries((results) => {
                if (results.length) {
                    entries = entries.concat(results);
                    readEntries();
                } else {
                    resolve(entries);
                }
            }, reject);
        }
        readEntries();
    });
}

function createDirectory(path) {
    return fetch(`/newfolder?data=${JSON.stringify({ foldername: path })}`, {
        method: 'POST'
    }).then(response => {
        if (response.ok) {
            showNotification("Directory " + path + " created successfully!");
            return response.text();
        } else {
            showError("Directory " + path + " upload failed!");
            throw new Error('Failed to create directory');
        }
    });
}

function uploadFileToServer(file, path) {
    return new Promise((resolve, reject) => {
        showNotification(" Uploading " + file.name + " Please wait... ");
        const reader = new FileReader();
        reader.onload = function(event) {
            const fileSize = event.target.result.byteLength;
            const hexData = hexEncode(event.target.result);

            const xhr = new XMLHttpRequest();
            xhr.open("POST", `/upload;${path};${fileSize}`, true);
            xhr.setRequestHeader("Content-Type", "text/plain");
            xhr.onreadystatechange = function() {
                if (xhr.readyState === XMLHttpRequest.DONE) {
                    if (xhr.status === 200) {
                        showNotification("File " + file.name + " uploaded successfully!");
                        resolve();
                    } else {
                        showError("Upload " + file.name + " failed!");
                        reject(new Error("Upload " + file.name + " failed"));
                    }
                }
            };
            xhr.send(hexData);
        };
        reader.readAsArrayBuffer(file);
    });
}

function hexEncode(buffer) {
    const byteArray = new Uint8Array(buffer);
    return Array.from(byteArray, byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
}


function resetPopupTimer() {
    clearTimeout(popupTimer);
    popupTimer = setTimeout(closePopup, 8000);
}

function showPopup(content) {
    document.getElementById('popup-content').innerHTML = content;
    document.getElementById('popup-overlay').style.display = 'flex';
    resetPopupTimer();
}

function closePopup() {
    document.getElementById('popup-overlay').style.display = 'none';
    popup_modal = false;
    clearTimeout(popupTimer);
}

function showError(message) {
    popup_modal = true;
    document.getElementById('popup-close').style.display = 'block';
    showPopup('<p style="color: red;">' + message + '</p>');
}

function showNotification(message) {
    popup_modal = true;
    document.getElementById('popup-close').style.display = 'block';
    showPopup('<p style="color: green;">' + message + '</p>');
}

function showLoading(message) {
    popup_modal = false;
    document.getElementById('popup-close').style.display = 'none';
    showPopup('<p style="color: black;">' + message + '</p>');
}

function downloadAll(urls) {
    var link = document.createElement('a');
    link.setAttribute('download', null);
    link.style.display = 'none';
    document.body.appendChild(link);

    for (var i = 0; i < urls.length; i++) {
        link.setAttribute('href', urls[i]);
        link.click();
    }
    document.body.removeChild(link);
}

function loadDirectoryContents(path) {
    currentPath = path;
    updateBreadcrumb();
    
    console.log("Updating file list");

    if (document.getElementById('popup-overlay').style.display == 'none') {
        showLoading("  Loading...  ");
    }

    fetch('/contents?path=' + currentPath)
        .then(response => response.json())
        .then(data => {
            const fileTable = document.getElementById('file-table').querySelector('tbody');
            fileTable.innerHTML = '';

            if (path !== '/') {
                const row = document.createElement('tr');
                const selectCell = document.createElement('td');
                const nameCell = document.createElement('td');
                nameCell.style.cursor = 'pointer';
                nameCell.addEventListener('click', () => loadDirectoryContents(path.substring(0, path.lastIndexOf('/')) || '/'));
                nameCell.innerHTML = `<img src="icons/up.png" class="file-icon"> ..`;

                const sizeCell = document.createElement('td');
                sizeCell.textContent = '';

                row.appendChild(selectCell);
                row.appendChild(nameCell);
                row.appendChild(sizeCell);
                fileTable.appendChild(row);
            }

            // Separate and sort directories and files
            const directories = data.contents.filter(file => file.isDirectory).sort((a, b) => a.name.localeCompare(b.name));
            const files = data.contents.filter(file => !file.isDirectory).sort((a, b) => a.name.localeCompare(b.name));

            // Combine sorted directories and files
            const sortedContents = directories.concat(files);

            sortedContents.forEach((file,index) => {
                const row = document.createElement('tr');
                const selectCell = document.createElement('td');
                const selectInput = document.createElement('input');
                selectInput.type = 'checkbox';
                selectInput.name = 'chkFile';
                selectInput.value = file.name;
    
                const label= document.createElement('label');
                label.appendChild(selectInput);
                label.appendChild(document.createTextNode(index+1));
                selectCell.appendChild(label);

                const nameCell = document.createElement('td');
                const iconSrc = file.isDirectory ? 'icons/folder.png':'icons/file.png'//folderIconBase64 : fileIconBase64;
                const icon = document.createElement('img');
                icon.className = 'file-icon';
                icon.src = iconSrc;
                if(/\.(js|txt|py|html|css|json|vue|scss|ini|config|conf|sql|log)$/.test(file.name)){
                    const link=document.createElement('a');
                    link.href='javascript:;'
                    link.addEventListener('click', () => showEditerDialog(file.path));
                    link.appendChild(icon)
                    link.appendChild(document.createTextNode(file.name))
                    nameCell.appendChild(link);
                }
                else{
                    nameCell.appendChild(icon);
                    nameCell.appendChild(document.createTextNode(file.name));
                }

                if (file.isDirectory) {
                    nameCell.style.cursor = 'pointer';
                    nameCell.addEventListener('click', () => loadDirectoryContents(file.path));
                }

                const sizeCell = document.createElement('td');
                sizeCell.textContent = file.isDirectory ? '-' : `${file.size} B`;

                row.appendChild(selectCell);
                row.appendChild(nameCell);
                row.appendChild(sizeCell);
                fileTable.appendChild(row);
            });

            if (popup_modal == false) {
                closePopup();
            }
        })
        .catch(error => {
            showError(error.message);
        });
}

function updateBreadcrumb() {
    const breadcrumb = document.getElementById('breadcrumb');
    breadcrumb.innerHTML = '';

    const pathParts = currentPath.split('/').filter(part => part);

    const link = document.createElement('a');
    link.href = 'javascript:loadDirectoryContents("/");';
    link.textContent = "\u00A0\u00A0/\u00A0\u00A0\u00A0";
    breadcrumb.appendChild(link);

    let path = '';
    pathParts.forEach((part, index) => {
        path += `/${part}`;
        const link = document.createElement('a');
        link.href = 'javascript:loadDirectoryContents("' + path + '");';
        link.textContent = part;

        breadcrumb.appendChild(link);
        if (index < pathParts.length - 1) {
            breadcrumb.appendChild(document.createTextNode(' / '));
        }
    });
}


const dialogFile=document.getElementById("dialogEditFile")
const txtFileContent=document.getElementById("txtFileContent")
const spanTile=document.getElementById("spanTile")

function showEditerDialog(file){
    fetch(`/download?path=${file}`)
    .then(res=>res.blob())
    .then(data=>{
        const reader = new FileReader();
        reader.onloadend = function(e) {      
            showEditer(file,e.target.result)
        }
        reader.readAsText(data)//readAsBinaryString(data)
    }).catch(error => {
        showError(error.message);
    });
}
function showEditer(file,txt){
    dialogFile.filepath=file
    txtFileContent.value=''
    spanTile.innerHTML=file 
    if(/\.(js|py|html|css|vue|)$/.test(file)){//使用编辑器显示代码文件内容 
        if(!window.fileEditor){
            window.fileEditor=CodeMirror.fromTextArea(txtFileContent, {
                autofocus:true,
                dragDrop:true,                        
                lineNumbers: true, // 显示行号
                lineWrapping: true, // 自动换行
                indentWithTabs: true, // 缩进替换tab为空格
                //mode: "htmlmixed", // 语法高亮
                gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], // 显示行号和折叠区域
                lint: true, // 自动纠错
                tabSize: 4, // 设置Tab键的缩进大小
                theme: "idea", // 主题
                cursorHeight: 1 // 光标高度 最大值1
            });
        } // 宽度自适应 高度100%
        window.fileEditor.setSize('auto','100vh');
        window.fileEditor.setOption("multiplex", [])
        const suffix=file.substring(file.lastIndexOf('.'))
        switch(suffix){
            case '.js':
                window.fileEditor.setOption("mode", "javascript")
                break
            case '.py':
                window.fileEditor.setOption("mode", "python")
                break
            case '.html':
                window.fileEditor.setOption("mode", "htmlmixed")
                break
            case '.css':
                window.fileEditor.setOption("mode", "css")
                break
            case '.vue':
                window.fileEditor.setOption("mode", "vue")
                break
        }
    }else{                
        if(window.fileEditor){//移除编辑器
            window.fileEditor.toTextArea();
            window.fileEditor=null
        }
    }
    dialogFile.showModal()
    if(txt)window.setTimeout(()=>{
        if(window.fileEditor)window.fileEditor.setValue(txt)
        else txtFileContent.value=txt
    },500)
}





